use std::sync::Arc;

use axum::{
    extract::{Json as ExtractJson, State},
    http::StatusCode,
    response::IntoResponse,
};
use serde::{Deserialize, Serialize};
use tracing::debug;

use bc_base::PublicKeyHashBytes;
use bc_lib::mining::MiningCommand;

use crate::AppState;

#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct MineRequest {
    account: String,
    action: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct MineResponse {
    message: String,
}

//
// curl -X POST http://localhost:3000/api/mine \
//      -H "Content-Type: application/json" \
//      -d '{"account": "目标账号", "action": "start"}'
//
// curl -X POST http://localhost:3000/api/mine \
//      -H "Content-Type: application/json" \
//      -d '{"account": "目标账号", "action": "pause"}'
//
// curl -X POST http://localhost:3000/api/mine \
//      -H "Content-Type: application/json" \
//      -d '{"account": "目标账号", "action": "stop"}'

pub(crate) async fn mine_block(
    State(state): State<Arc<AppState>>,
    ExtractJson(body): ExtractJson<MineRequest>,
) -> impl IntoResponse {
    let MineRequest { account, action } = body;

    match action.as_str() {
        "start" => {
            // 启动挖矿逻辑
            let miner_id = PublicKeyHashBytes::from_hex_str(&account);
            match miner_id {
                Ok(miner_id) => {
                    start_mining(&state, miner_id).await;
                    (
                        StatusCode::OK,
                        ExtractJson(MineResponse {
                            message: "挖矿已启动".to_string(),
                        }),
                    )
                }
                Err(e) => {
                    let msg = format!("The account format is invalid ({}).", e);

                    (
                        StatusCode::BAD_REQUEST,
                        ExtractJson(MineResponse { message: msg }),
                    )
                }
            }
        }
        "pause" => {
            // 暂停挖矿逻辑
            pause_mining(&state).await;
            (
                StatusCode::OK,
                ExtractJson(MineResponse {
                    message: "挖矿已暂停".to_string(),
                }),
            )
        }
        "stop" => {
            // 停止挖矿逻辑
            stop_mining(&state).await;
            (
                StatusCode::OK,
                ExtractJson(MineResponse {
                    message: "挖矿已停止".to_string(),
                }),
            )
        }
        _ => (
            StatusCode::BAD_REQUEST,
            ExtractJson(MineResponse {
                message: "无效的操作".to_string(),
            }),
        ),
    }
}

async fn start_mining(state: &Arc<AppState>, miner_id: PublicKeyHashBytes) {
    debug!("启动挖矿，目标账号: {}", miner_id.to_hex_str());

    let mng = state.bc_manager.lock().await;
    mng.send_cmd_to_ming_task(MiningCommand::Start(miner_id))
        .await;
}

async fn pause_mining(state: &Arc<AppState>) {
    debug!("暂停挖矿");
    let mng = state.bc_manager.lock().await;
    mng.send_cmd_to_ming_task(MiningCommand::Pause).await;
}

async fn stop_mining(state: &Arc<AppState>) {
    debug!("停止挖矿");
    let mng = state.bc_manager.lock().await;
    mng.send_cmd_to_ming_task(MiningCommand::Stop).await;
}
